/********************************************************************************
* Description: this is a POD object
* Author: hsqiang
* Create Date: 2023-06-23
********************************************************************************/
#ifndef SOCKET_HPP_
#define SOCKET_HPP_

#include "end_point.hpp"
#include <vector>
#include <utility>

namespace event_framework
{
    class Socket final
    {
    public:
        explicit Socket(const EndPoint& ep) : endpoint(ep) {}
        explicit Socket(const EndPoint& ep, int fd_) : endpoint(ep), fd(fd_) {}
        ~Socket()
        {
            Close();
        }
        int Create(int family, int type, int protocol)
        {
            ASSERT(fd < 0);
            fd = socket(family, type, protocol);
            return fd;
        }
        int Bind()
        {
            return bind(fd, endpoint.GetAddrPtr(), endpoint.GetAddrLen());
        }
        int Listen(int backlog)
        {
            return listen(fd, backlog);
        }
        int Accept(EndPoint& peer)
        {
            sockaddr addr;
            socklen_t addrLen;
            auto ret = accept(fd, &addr, &addrLen);
            peer = EndPoint(*((struct sockaddr_in*)&addr));
            return ret;
        }
        int Connect(const EndPoint& peer)
        {
            return connect(fd, peer.GetAddrPtr(), peer.GetAddrLen());
        }
        // for tcp
        int Send(char* buff, int len)
        {
            return send(fd, buff, len, 0);
        }
        int Sendto(const EndPoint& peer, char* buff, int len)
        {
            return sendto(fd, buff, len, 0, peer.GetAddrPtr(), peer.GetAddrLen());
        }
        int Sendmsg(const EndPoint& peer, const std::vector<std::pair<char*, int>>& bufvec);
        // for tcp
        int Writev(const std::vector<std::pair<char*, int>>& bufvec);
        // for tcp
        int Recv(char* buff, int len)
        {
            return recv(fd, buff, len, 0);
        }
        int Recvfrom(const EndPoint& peer, char* buff, int len)
        {
            socklen_t addrlen = peer.GetAddrLen();
            return recvfrom(fd, buff, len, 0, const_cast<sockaddr*>(peer.GetAddrPtr()), &addrlen);
        }
        int Recvmsg(const EndPoint& peer, std::vector<std::pair<char*, int>>& bufvec);
        // for tcp
        int Readv(std::vector<std::pair<char*, int>>& bufvec);
        void Close();
        int GetFd() const { return fd; }
        const EndPoint& GetEndPoint()
        {
            return endpoint;
        }
    private:
        int fd { -1 };
        EndPoint endpoint;
    };
}

#endif